#include <glf.h>
#include <glfwindow.h>
#include <glfu.h>

//GL program handle
static GLuint programHandle = 0;

//Vertex attribute location
static GLint vertexLocation = -1;
static GLint texCoordLocation = -1;

//Vertex uniform location;
static GLint diffuseMapLocation = -1;

static GLint diffuseTexture = 0;

//Draw program attributes
static const int programAttributes[]=
{ 
	GL_VERTEX_SHADER, (int)"sampler2d.vert", 
	GL_FRAGMENT_SHADER, (int)"sampler2d.frag", 
	0 
};

//Vertex data
static const float	positions[12]={
	
	1,-1,
	1,1,
	-1,1,

	1,-1,
	-1,1,
	-1,-1

};

static const float texCoords[12]={
	1,0,
	1,1,
	0,1,
	1,0,
	0,1,
	0,0
};

static void initialise(void* userdata)
{
	glfuTextureData2d_t textureData;
	programHandle = glfuLoadProgram( programAttributes );
	if( programHandle != 0 )
	{
		glUseProgram( programHandle );
		vertexLocation = glGetAttribLocation( programHandle, "vertex" );
		if( vertexLocation != -1 )
		{
			glEnableVertexAttribArray( vertexLocation );
			glVertexAttribPointer( vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, positions );
		}
		texCoordLocation = glGetAttribLocation( programHandle, "texCoord" );
		if( texCoordLocation != -1 )
		{
			glEnableVertexAttribArray( texCoordLocation );
			glVertexAttribPointer( texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texCoords );
		}
		diffuseMapLocation = glGetUniformLocation( programHandle, "diffuseMap" );
		if( diffuseMapLocation != -1 )
		{
			glUniform1i( diffuseMapLocation, 0 );
		}
	}
	glGenTextures( 1, &diffuseTexture );
	if( diffuseTexture != 0 )
	{
		glBindTexture( GL_TEXTURE_2D, diffuseTexture );
		if( glfuLoadTextureData2dTga( &textureData, "sampler2d.tga" ) == 0 )
		{
			glTexImage2D( GL_TEXTURE_2D, 0, textureData.format, textureData.width, textureData.height, 0, textureData.format, GL_UNSIGNED_BYTE, textureData.data ); 
			glGenerateMipmap( GL_TEXTURE_2D );
		}
		else
		{
			glDeleteTextures( 1, &diffuseTexture );
			diffuseTexture = 0;
		}
	}
}

static void terminate(void* userdata)
{
	if( diffuseTexture != 0 )
	{
		glTexImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0, 0 ); 
		glGenerateMipmap( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, 0 );
		glDeleteTextures( 1, &diffuseTexture );
		diffuseTexture = 0;
	}
	diffuseMapLocation = -1;
	if( texCoordLocation != -1 )
	{
		glVertexAttribPointer( texCoordLocation, 0, 0, 0, 0, 0 );
		glDisableVertexAttribArray( texCoordLocation );
		texCoordLocation = -1;
	}
	if( vertexLocation != -1 )
	{
		glVertexAttribPointer( vertexLocation, 0, 0, 0, 0, 0 );
		glDisableVertexAttribArray( vertexLocation );
		vertexLocation = -1;
	}
	if( programHandle != 0 )
	{
		glUseProgram( 0 );
		glfuUnloadProgram( programHandle );
		programHandle = 0;
	}
}

static void think(void* userdata)
{
}

static void render(void* userdata)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glDrawArrays( GL_TRIANGLES, 0, 6 );
}

static void resize(void* userdata)
{
	glViewport(0,0,glfGetWidth(),glfGetHeight());
}

int main(void)
{

	glfConfigSetAttribute(glfMajorVersion, 3);
	glfConfigSetAttribute(glfMinorVersion, 1);
	glfConfigSetAttribute(glfContextFlags, glfContextForwardCompatible);

	if( !glfCreateWindow( "Sampler2D", 640, 480 ) )
	{
		return -1;
	}

	glfSetCallBack(glfCallbackInitialise, initialise, NULL );
	glfSetCallBack(glfCallbackThink, think, NULL );
	glfSetCallBack(glfCallbackRender, render, NULL );
	glfSetCallBack(glfCallbackResize, resize, NULL );
	glfSetCallBack(glfCallbackTerminate, terminate, NULL );

	if( !glfMainloop() )
	{
		return -1;
	}

	glfDestroyWindow();

	return 0;
}
